package com.sailor.util;


import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import com.sailor.annotation.SensitiveField;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Objects;

/**
 * @Author: sailor
 * @Description: 加密工具类
 */
public class EncryptUtil {

    private EncryptUtil() {
        throw new IllegalStateException("Utility class");
    }

    private static final String SAILOR_DEFAULT = "「SAILOR.COM」©2022";

    private static final String SALT = sha1(SAILOR_DEFAULT, true);

    private static final SecretKeySpec AES_KEY = getSecretKey(SALT);

    public static String sha1(String str, boolean upper) {
        String enc = Hashing.sha256().hashString(str, StandardCharsets.UTF_8).toString();
        return upper ? enc.toUpperCase() : enc;
    }

    /**
     * AES加密字符串
     *
     * @param content  需要被加密的字符串
     * @param password 加密需要的密码
     * @return 密文
     */
    private static final String KEY_ALGORITHM = "AES";

    public static <T> T encrypt(Field[] declaredFields, T paramsObject) throws IllegalAccessException {
        for (Field field : declaredFields) {
            //取出所有被EncryptDecryptField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (!Objects.isNull(sensitiveField)) {
                field.setAccessible(true);
                Object object = field.get(paramsObject);
                //暂时只实现String类型的加密
                if (object instanceof String) {
                    String value = (String) object;
                    //加密  这里我使用自定义的AES加密工具
                    field.set(paramsObject, encryptByAES(value));
                }
            }
        }
        return paramsObject;
    }

    public static <T> T decrypt(T result) throws IllegalAccessException {
        //取出resultType的类
        Class<?> resultClass = result.getClass();
        Field[] declaredFields = resultClass.getDeclaredFields();
        for (Field field : declaredFields) {
            //取出所有被EncryptDecryptField注解的字段
            SensitiveField sensitiveField = field.getAnnotation(SensitiveField.class);
            if (!Objects.isNull(sensitiveField)) {
                field.setAccessible(true);
                Object object = field.get(result);
                //暂时只支持String的解密
                if (object instanceof String) {
                    String value = (String) object;
                    //对注解的字段进行逐一解密
                    field.set(result, decryptByAES(value));
                }
            }
        }
        return result;
    }

    public static String encryptByAES(String content) {
        if (StringUtils.isBlank(content)) {
            return content;
        }
        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            byte[] byteContent = content.getBytes(Charsets.UTF_8);
            // 初始化为加密模式的密码器
            cipher.init(Cipher.ENCRYPT_MODE, AES_KEY);
            // 加密
            return Base64.getEncoder().encodeToString(cipher.doFinal(byteContent));
        } catch (Exception e) {
//            SystemErrorLogUtil.error(e, "加密字符串异常:{}", content);
            throw new RuntimeException("加密字符串异常", e);
        }
    }

    /**
     * 解密AES加密过的字符串
     *
     * @param encContent AES加密过过的内容
     * @return 明文
     */
    public static String decryptByAES(String encContent) {
        if (StringUtils.isBlank(encContent)) {
            return encContent;
        }
        try {
            // 创建密码器
            Cipher cipher = Cipher.getInstance(KEY_ALGORITHM);
            // 初始化为解密模式的密码器
            cipher.init(Cipher.DECRYPT_MODE, AES_KEY);
            return new String(cipher.doFinal(Base64.getDecoder().decode(encContent)), Charsets.UTF_8);
        } catch (Exception e) {
//            SystemErrorLogUtil.error(e, "解密字符串异常:{}", encContent);
            //历史数据依赖正常返回，这里异常返回原始数据
            return encContent;
        }
    }

    /**
     * 生成AES加密秘钥
     *
     * @return
     */
    private static SecretKeySpec getSecretKey(final String password) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] thedigest = md.digest(password.getBytes(Charsets.UTF_8));
            // 转换为AES专用密钥
            return new SecretKeySpec(thedigest, KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成加密秘钥异常", e);
        }
    }

    /**
     * 生成AES加密随机秘钥
     *
     * @return
     */
    private static SecretKeySpec getRandomSecretKey(String password) {
        try {
            //返回生成指定算法密钥生成器的 KeyGenerator 对象
            KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
            //AES 要求密钥长度为 128
            kgen.init(128, new SecureRandom(password.getBytes()));
            SecretKey secretKey = kgen.generateKey();
            // 根据用户密码，生成一个密钥
            byte[] enCodeFormat = secretKey.getEncoded();
            // 返回基本编码格式的密钥
            // 转换为AES专用密钥
            return new SecretKeySpec(enCodeFormat, KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("生成加密秘钥异常", e);
        }
    }

}

